#include <iostream>
using namespace std;
#define MAXSIZE 10;
typedef char ElemType;

typedef struct LNode
{
  ElemType data;
  struct LNode *next;
  // 这里不是结构体嵌套LNode结构体里嵌套了个struct LNode，这样是死循环的，
  // 这里是结构体指针，因为要指向的下一个数据类型是LNode这个结构体，所以就要用结构体指针
  // 在C语言中，定义指针时，指针前的数据类型用来指定指针所指向的数据类型。
  // 这个数据类型告诉编译器在解引用指针时应该如何解释指针所指向的内存空间。
  // 这里的LinkNode和LNode是一个结构体，虽然一样，但是也不能定义成一个东西,反正就是不能写成一样的
} LinkNode;

// typedef struct LNode LinkNode;上面的一布其实是两步正常使用LNode要struct LNode缺一不可，但是现在可以用LinkNode表示

void InitLinkNode(LinkNode *&phead) // 初始化链表
{
  phead = (LinkNode *)malloc(sizeof(LinkNode));
  phead->next = NULL;
}

void CreatLinkNode(LinkNode *&phead, ElemType a[], int n) // 头插法
{
  LinkNode *s; // 要插入的数据
  for (int i = 0; i < n; i++)
  {
    s = (LinkNode *)malloc(sizeof(LinkNode)); // 动态开辟新插入的数据的内存空间
    s->data = a[i];                           // 将数据传送到新节点里
    s->next = phead->next;                    // 将s节点的指针指向链表的头节点后，相当于现在的头节点和s节点都可以访问头节点的下一个节点
    phead->next = s;                          // 断开头节点与头节点之后的联系，将头节点指向新增的s节点上
  }
}

void LinkNodePrint(LinkNode *phead) // 输出链表
{
  phead = phead->next;
  while (phead != NULL)
  {
    cout << phead->data << " ";
    phead = phead->next;
  }
  cout << endl;
}

int LinkNodeLength(LinkNode *phead) // 求链表的数据长度
{
  int n = 0;
  phead = phead->next;
  while (phead != NULL)
  {
    n++;
    phead = phead->next;
  }
  return n;
}

bool LinkNodeEmpty(LinkNode *phead) // 判断是否为空
{
  phead = phead->next;
  if (phead == NULL)
    return true;
  else
    return false;
}

ElemType LinkNodeGet(LinkNode *phead, int n) // 返回链表第N个元素
{
  int j = 0;  // 求链表的长度,用来判断n与长度的关系，判断完后，可以单独用for循环来输出第N个元素，也可以写在while里求长度的同时同时输出元素
  if (n <= 0) // 如果输入的n小于等于0那就无意义
    return false;
  phead = phead->next;  // 现在的phead表示第一个有数据的节点
  while (phead != NULL) // 和输出的语句意思一样
  {
    j++;        // 记录这是第几个元素
    if (j == n) // 如果返回的N与现在的数据节点相等的话就直接返回
      return phead->data;
    phead = phead->next; // 和输出的语句意思一样
  }
  return false;
}

int LinkNodeLocate(LinkNode *phead, ElemType i) // 查询元素i的位置
{
  int j = 0;
  phead = phead->next;
  while (phead != NULL)
  {
    j++;
    if (phead->data == i) // 如果相等，返回，上面和计数一样，一边计数一边判断是否相等
      return j;
    phead = phead->next;
  }
  return false;
}

bool LinkNodeInsert(LinkNode *&phead, int i, ElemType n) // 在第i个位置插入元素n，也可以当成尾插，就是链表只有一个长度，可以在第二个位置插入
{
  if (i <= 0)
    return false;
  int j = 0;
  LinkNode *l = phead; // 因为传入的phead是引用模式，所以不能使用phead=phead->next，因为这样就把链表删减了，所以要找个形参表示链表
  LinkNode *s;
  while (l != NULL && j < i - 1) // 插入数据到链表，要找到第i-1个节点是关键,查找第i-1个节点，从没有数据的头节点开始，因为如果插入位置是1的话就是0-1之间
  {
    j++;
    l = l->next; // 找到i-1个节点,到这里，l是第i-1个节点的首地址
  }
  if (l == NULL) // 如果第i-1个节点为空，插入失败
    return false;
  else
  {
    s = (LinkNode *)malloc(sizeof(LinkNode));
    s->data = n;
    s->next = l->next; // 将新建的s节点的指针指向现在第i-1的phead->next也就是第i个节点的位置
    l->next = s;       // 将新增的节点的首地址给i-1个next
    return true;
  }
}

bool LinkNodeDelete(LinkNode *phead, int i) // 删除第i个元素
{
  if (i <= 0)
    return false;
  int j = 0;
  LinkNode *l = phead;
  LinkNode *s;
  while (l != NULL && j < i - 1) // 删除第i元素，不仅要找到第i-1个元素还要找第i+1个元素，而插入只要找到第i-1个元素就好，因为第i+1个元素是空也可以插入的
  {
    j++;
    l = l->next;
  }
  if (l == NULL) // 判断第i-1个节点是否为空
    return false;
  else
  {
    s = l->next; // 现在的s是第i个节点的首地址
    if (s == NULL)
      return false;
    else
    {
      if (s->next == NULL) // 如果第i+1个节点为空，就直接把i-1的指针为空就好
      {
        l->next = NULL;
        free(s);
      }
      else
      {
        l->next = s->next;
        free(s);
      }
    }
    return true;
  }
}

void LinkNodeDestory(LinkNode *&phead) // 销毁链表
{
  LinkNode *pre = phead, *p = phead->next; // 双链表法，pre指向头节点，p指向有数据的首节点，若p不为空，则释放pre的节点，然后双双后移，若p为空，则退出循环释放最后的pre
  while (p != NULL)
  {
    free(pre);
    pre = p;
    p = p->next;
  }
  free(pre);
}

void LinkNodeBackInsert(LinkNode *&phead, ElemType a[], int n) // 尾插法
{
  LinkNode *l = phead;
  while (l->next != NULL)
  {
    l = l->next;
  } // l退出循环后就是表示尾节点
  for (int i = 0; i < n; i++)
  {
    LinkNode *s = (LinkNode *)malloc(sizeof(LinkNode));
    s->data = a[i];
    l->next = s;
    l = s; // 新增的s节点变成尾节点
  }
  l->next = NULL;
}

int main()
{
  LinkNode *phead;
  InitLinkNode(phead);
  int i = 0;
  cin >> i;
  int j = 0;
  cin >> j;
  cout << "(1)初始化单链表h" << endl;
  ElemType a[5] = {'a', 'b', 'c', 'd', 'e'};
  cout << "(2)依次采用尾插法插入a,b,c,d,e元素" << endl;
  LinkNodeBackInsert(phead, a, 5);
  // CreatLinkNode(phead, a, 5);
  cout << "(3)输出单链表h:";
  LinkNodePrint(phead);
  cout << "(4)单链表h长度:";
  cout << LinkNodeLength(phead) << endl;
  if (LinkNodeEmpty(phead) == true)
    cout << "(5)单链表h为空" << endl;
  else
    cout << "(5)单链表h为非空" << endl;
  cout << "(6)单链表h的第" << i << "个元素:" << LinkNodeGet(phead, i) << endl;
  cout << "(7)元素a的位置:";
  cout << LinkNodeLocate(phead, 'a') << endl;
  cout << "(8)在第" << j << "个元素位置上插入f元素" << endl;
  LinkNodeInsert(phead, j, 'f');
  cout << "(9)输出单链表h:";
  LinkNodePrint(phead);
  cout << "(10)删除h的第" << i << "个元素" << endl;
  LinkNodeDelete(phead, i);
  cout << "(11)输出单链表h:";
  LinkNodePrint(phead);
  LinkNodeDestory(phead);
  cout << "(12)释放单链表h";
  // LinkNodePrint(phead);
  return 0;
}